﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DriveBeamEditor.Controls.BeamNG.VehiclePartConfig;
using DriveBeamEditor.Controls.General;
using JBeamLibrary.Tools;
using JBeamLibrary.VehicleParts.Elements;
using JBeamLibrary.VehicleParts.Enums;

namespace DriveBeamEditor.Controls.BeamNG.SectionControls
{
    public partial class FlexbodiesControl : VehiclePartControl
    {
        #region Properties

        private ElementPropertyUse PropertyUse
        {
            get { return rbGroupProp.Checked ? ElementPropertyUse.Group : ElementPropertyUse.Single; }
        }

        public Flexbody CurrentFlexbody
        {
            get { return bindingSource.Current as Flexbody; }
        }

        #endregion

        #region CTORs

        public FlexbodiesControl()
        {
            InitializeComponent();
        }

        #endregion

        #region Events

        #region Binding sources

        private void bindingSource_AddingNew(object sender, AddingNewEventArgs e)
        {
            if (DesignMode || VehiclePart == null)
            {
                e.NewObject = new Flexbody();
                return;
            }

            /* Avoid loop */
            if (e.NewObject is Flexbody) return;

            /* Create a new material */
            e.NewObject = new Flexbody(Randomizer.GetRandomName());
        }

        private void bindingSource_CurrentChanged(object sender, EventArgs e)
        {
            BindGroups();
            BindNonFlexMaterials();

            /* No vehicle part loaded */
            if (VehiclePart == null) return;

            /* Update property box title */
            boxProperties.Text =
                CurrentFlexbody != null
                ? string.Format("Flexbody '{0}' properties", CurrentFlexbody)
                : @"Flexbody properties";

            /* Display properties */
            UpdateProperties(bindingSource.Position);
        }

        #endregion

        #region Data grid view

        private void gridMeshes_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            gridMeshes_CellContentClick(sender, e);
        }

        private void gridMeshes_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            /* Clicks on headers */
            if (e.ColumnIndex < 0 || e.RowIndex < 0) return;

            /* Get column & row & cell */
            var col = gridMeshes.Columns[e.ColumnIndex];
            var row = gridMeshes.Rows[e.RowIndex];

            /* Validate new row */
            if (row.IsNewRow && col == columnDelete)
            {
                bindingSource.EndEdit();
                gridMeshes.NotifyCurrentCellDirty(true);
                gridMeshes.EndEdit();
                gridMeshes.NotifyCurrentCellDirty(false);
            }

            /* Delete the current row */
            else if (col == columnDelete)
            {
                gridMeshes.Rows.RemoveAt(e.RowIndex);
            }
        }

        #endregion

        #region Radio buttons

        private void rbGroupProp_CheckedChanged(object sender, EventArgs e)
        {
            if (rbGroupProp.Checked)
                OnPropertyUseChanged();
        }

        private void rbInlineProp_CheckedChanged(object sender, EventArgs e)
        {
            if (rbInlineProp.Checked)
                OnPropertyUseChanged();
        }

        #endregion

        #region Buttons

        private void xbAddGroup_Click(object sender, EventArgs e)
        {
            if (CurrentFlexbody == null) return;
            if (string.IsNullOrEmpty(tbGroup.Text))
            {
                MessageBox.Show(this, @"Please enter a group name", @"No group name specified", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            CurrentFlexbody.Groups.Add(tbGroup.Text);
            bindingSourceGroups.ResetBindings(false);
        }

        private void xbRemoveGroup_Click(object sender, EventArgs e)
        {
            if (CurrentFlexbody == null || listGroups.SelectedIndex < 0) return;
            CurrentFlexbody.Groups.RemoveAt(listGroups.SelectedIndex);
            bindingSourceGroups.ResetBindings(false);
        }

        private void xbAddNonFlexMaterial_Click(object sender, EventArgs e)
        {
            if (CurrentFlexbody == null) return;
            if (string.IsNullOrEmpty(tbNonFlexMaterial.Text))
            {
                MessageBox.Show(this, @"Please enter a non-flex. material name", @"No material specified", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            CurrentFlexbody.NonFlexMaterials.Add(tbNonFlexMaterial.Text);
            bindingSourceNonFlexMaterials.ResetBindings(false);
        }

        private void xbRemoveNonFlexMaterial_Click(object sender, EventArgs e)
        {
            if (CurrentFlexbody == null || listNonFlexMaterials.SelectedIndex < 0) return;
            CurrentFlexbody.NonFlexMaterials.RemoveAt(listNonFlexMaterials.SelectedIndex);
            bindingSourceNonFlexMaterials.ResetBindings(false);
        }

        #endregion

        #region Property editors

        private void kvcEditor_EditValueChanged(object sender, EventArgs e)
        {
            var editor = sender as KeyValueControl;
            if (editor == null) return;

            /* Set the property value */
            var properties = VehiclePart.FlexbodySection.Properties;
            var index = bindingSource.Position;
            properties.SetPropertyValue(index, editor.Key, PropertyUse, editor.EditValue);
        }

        #endregion

        #endregion

        #region Methods

        public override string ToString()
        {
            return "Flexbodies";
        }

        private void BindFlexbodies()
        {
            gridMeshes.Enabled = false;
            bindingSource.DataSource = null;

            if (VehiclePart != null)
                bindingSource.DataSource = VehiclePart.FlexbodySection.ElementCollection;

            gridMeshes.Refresh();
            gridMeshes.Enabled = true;
        }

        private void BindGroups()
        {
            if (VehiclePart != null && CurrentFlexbody != null)
                bindingSourceGroups.DataSource = CurrentFlexbody.Groups;
            else
                bindingSourceGroups.DataSource = null;

            bindingSourceGroups.ResetBindings(false);
        }

        private void BindNonFlexMaterials()
        {
            if (VehiclePart != null && CurrentFlexbody != null)
                bindingSourceNonFlexMaterials.DataSource = CurrentFlexbody.NonFlexMaterials;
            else
                bindingSourceNonFlexMaterials.DataSource = null;

            bindingSourceNonFlexMaterials.ResetBindings(false);
        }

        protected override void OnVehiclePartChanged()
        {
            BindFlexbodies();
            base.OnVehiclePartChanged();
        }

        private void OnPropertyUseChanged()
        {
            UpdateProperties(bindingSource.Position);
        }

        private void UpdateProperties(int index)
        {
            foreach (var editor in
                from editor in boxProperties.Controls.OfType<KeyValueControl>()
                select editor
            )
            {
                var val = GroupHelper.GetPropertyValue(VehiclePart.FlexbodySection, index, editor.Key, PropertyUse);
                editor.SetEditValueSilent(val);
            }
        }

        #endregion
    }
}
